/*

storage.js

Copyright (C) 2012 Fraunhofer Institute for Secure Information Technology

Authors: Steven Arzt <steven.arzt@sit.fraunhofer.de>
         Oliver Hoffmann <oliver.hoffmann@sit.fraunhofer.de>
         Sebastian Ruhleder <sebastian.ruhleder@sit.fraunhofer.de>
		 
Contact: Andreas Poller <andreas.poller@sit.fraunhofer.de>
         Fraunhofer Institute for Secure Information Technology
		 Rheinstraße 75
		 64295 Darmstadt
		 Germany

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/gpl-3.0.txt>.

*/

/* Interactions and rose comments arrays. */
var _interactions = null;

/* Heartbeat. */
var _heartbeat = null;

/* Initialized flag. */
var storageInitialized = false;

// Register the listener for external changes to the storage objects
if (typeof kango != "undefined") {
	kango.addMessageListener('ReloadStorage', function(event) {
		initStorage();
	});
}

/*
 * Initializes storage.
 */

function initStorage() {
	try {
		// Set handlers.
		window.getInteractionData = _getInteractionData;
		window.deleteInteractionData = _deleteInteractionData;
		window.deleteCommentData = _deleteCommentData;
		window.getCommentData = _getCommentData;

		// Check what type of storage to ues.
		if (STORAGE_TYPE == STORAGE_TYPE_LOCAL) {
			log("Initializing local storage.");

			// Get ROSE data.
			var roseData = $.jStorage.get("roseData", null);

			// Get interactions.
			_interactions = roseData["interactions"];

			// Get ROSE comments.
			_roseComments = roseData["roseComments"];

			// Get heartbeat.
			_heartbeat = roseData["heartbeat"];

			// Create new, if they haven't been set.
			if (!_interactions) {
				_interactions = [];
			}
			if (!_roseComments) {
				_roseComments = {};
			}
			if (!_heartbeat) {
				_heartbeat = new Date();
			}

			// Set initialized flag.
			storageInitialized = true;
		} else if (STORAGE_TYPE == STORAGE_TYPE_KANGO) {
			log("Initializing kango storage.");

			// Invoke kango storage.
			kango.invokeAsync('kango.storage.getItem', 'roseData', function(data) {
				if ((typeof data != "undefined") && data) {
					_interactions = $.extend(true, [], data["interactions"]);
					_roseComments = $.extend(true, {}, data["roseComments"]);
					_heartbeat = data["heartbeat"];
				} else {
					_interactions = null;
					_roseComments = null;
					_heartbeat = null;
				}

				if (!_interactions) _interactions = [];
				log("Kango interaction store ready.");

				if (!_roseComments) _roseComments = {};
				log("Kango study comment store ready.");

				if (!_heartbeat) _heartbeat = new Date();
				log("Kango heartbeat ready.");

				// Set initialized flag.
				storageInitialized = true;
			});
		} else {
			throw new Error("Unkown storage type.");
		}
	} catch (exception) {
		alert("[ROSE] Could not initialize storage: " + exception);
	}
}

/*
 * Saves storage.
 */

function saveStorage() {
	try {
		// Create container with interactions and comments.
		var container = {};
		container["interactions"] = _interactions;
		container["roseComments"] = _roseComments;
		container["heartbeat"] = _heartbeat;

		if (STORAGE_TYPE_KANGO == STORAGE_TYPE_LOCAL) {
			// Store in local storage.
			$.jStorage.set("roseData", container);
		} else if (STORAGE_TYPE_KANGO == STORAGE_TYPE) {
			// Store in kango storage.
			if (typeof kango.storage == 'undefined') {
				kango.invokeAsync('kango.storage.setItem', 'roseData', container);
			} else {
				kango.storage.setItem('roseData', container);
			}
		} else {
			// Storage type unknown.
			throw new Error("Unknown storage type.");
		}
	} catch (ex) {
		alert("[ROSE] Could not serialize data objects.");
	}
}

/*
 * Returns the next interaction number.
 */

function getNextInteractionNumber() {
	// If no interaction known, return 0.
	if (_interactions.length === 0) {
		return 0;
	}

	// Return increased interaction number.
	return _interactions[_interactions.length - 1]["nr"] + 1;
}

/*
 * Saves a given interaction directly to the storage.
 */

function saveInteraction(interaction) {
	// If interactions array is not ready, stall.
	if (_interactions === null) {
		setTimeout(function() {
			saveInteraction(interaction);
		}, 500);
	} else {
		try {
			// Add interaction number.
			interaction["nr"] = getNextInteractionNumber();
		} catch (exception) {
			log("Error reading interaction number; omitted.");
		}

		// Push interaction to array.
		try {
			_interactions.push(interaction);
		} catch (exception) {
			alert("[ROSE] failed to store interactions");
		}

		// Log interaction.
		log("Interaction: " + JSON.stringify(interaction));
		saveStorage();
	}
}

/*
 * Removes an interaction by its interaction number.
 */

function removeInteraction(nr) {
	// Traverse interactions.
	for (var i = 0; i < _interactions.length; i++) {
		// Get current interaction.
		var interaction = _interactions[i];

		// Check if interaction should be deleted.
		if (interaction["nr"] == nr) {
			// Remove from _interactions array.
			_interactions.splice(i, 1);

			// Save storage.
			saveStorage();

			// Notify all instances.
			notifyStorageChanged();

			// Return success.
			return true;
		}
	}
	// Nothing done? Return false.
	return false;
}

/*
 * Returns type of last open/close interaction.
 */

function getLastOpenCloseInteraction() {
	// If interactions aren't available, return error.
	if (_interactions === null) {
		return "error";
	}

	// Iterate through interactions.
	for (var i = _interactions.length - 1; i >= 0; i--) {
		// Check if interaction is valid.
		if (!_interactions[i].hasOwnProperty("interaction_type")) {
			continue;
		}

		// Get interaction type.
		var interactionType = _interactions[i]['interaction_type'];

		// Check, if open/close interaction.
		if (interactionType == "openFacebook" || interactionType == "closeFacebook") {
			return interactionType;
		}
	}

	// Nothing found? Return error.
	return "error";
}

/*
 * Updates heartbeat to current timestamp.
 */

function setHeartbeat() {
	_heartbeat = new Date();

	// Save storage.
	saveStorage();
}

/*
 * Gets heartbeat.
 */

function getHeartbeat() {
	if (typeof _heartbeat === Date) {
		return _heartbeat;
	}
	else {
		return new Date(_heartbeat);
	}
}

/*
 * Removes an comment by its hash.
 */
var removeComment = function(key) {
	delete _roseComments[key];
	saveStorage();
	return notifyStorageChanged();
};

/*
 * Handler for ROSE UI, gets interaction data.
 */

function _getInteractionData(callback) {
	try {
		callback(_interactions);
	} catch (exception) {
		alert("[ROSE] Error while retrieving interaction data.");
	}
}

/*
 * Handler for ROSE UI, deletes interaction data.
 */

function _deleteInteractionData() {
	log("Delete interaction data.");
	try {
		// If we are not initialized yet, throw an error
		if (!storageInitialized) {
			throw new Error("ROSE plugin is not yet initialized");
		}
		_interactions = [];
		saveStorage();
		notifyStorageChanged();
	} catch (ex) {
		alert("[ROSE] Could not delete interaction data: " + ex);
	}
}

/*
 * Handler for ROSE UI.
 */

function _getCommentData(callback) {
	try {
		callback(_roseComments);
	} catch (exception) {
		alert("[ROSE] Error while retrieving interaction data.");
	}
}

/*
 * Handler for ROSE UI, deletes interaction data.
 */

function _deleteCommentData() {
	log("Delete comment data.");
	try {
		// If we are not initialized yet, throw an error
		if (!storageInitialized) {
			throw new Error("ROSE plugin is not yet initialized");
		}
		_roseComments = {};
		saveStorage();
		notifyStorageChanged();
	} catch (ex) {
		alert("[ROSE] Could not delete comment data: " + ex);
	}
}

// Notifies the content script that the storage has been changed and needs to
// be reloaded.

function notifyStorageChanged() {
	if ((typeof kango.browser == "undefined") || (typeof kango.browser.tabs == "undefined")) {
		return;
	}

	// Notify the content scripts that the storage must be reloaded.
	kango.browser.tabs.getAll(function(tabs) {
		for (var i = 0; i < tabs.length; i++) {
			tabs[i].dispatchMessage('ReloadStorage', '');
		}
	});
}

/*
 * Gets a comment out of the local storage indicated by a given token
 */
var getCommentByToken = function(token) {
	var key = hash(token);
	return typeof _roseComments !== "undefined" && _roseComments !== null ? _roseComments[key] : void 0;
};

/*
 * Adds a new comment to the local kango storage as a key/value pair
 * token / comment
 */
var setCommentByToken = function(token, comment) {
	var key = hash(token);
	if (typeof _roseComments !== "undefined" && _roseComments !== null) {
		try {
			_roseComments[key] = comment;
		} catch (exception) {
			alert("[ROSE] failed to store comment");
			alert(exception);

			kango.invokeAsync('kango.storage.getItem', 'roseData', function(data) {
				if ((typeof data != "undefined") && data) {
					_roseComments = data["roseComments"];

					if (typeof _roseComments !== "undefined" && _roseComments !== null) {
						try {
							_roseComments[key] = comment;
						} catch (exception) {
							alert("[ROSE] failed second try to store comment");
							alert(exception);
						}
					}
				}
			});
		}
	}
	return saveStorage();
};

var createCookie = function(name, value, days) {
	var expires = "";
	if (days) {
		var date = new Date();
		date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
		expires = "; expires=" + date.toGMTString();
	}
	document.cookie = name + "=" + value + expires + "; path=/";
};

var isReminderActive = function(cb) {
	kango.invokeAsync('kango.storage.getItem', 'rose-settings', function(settings) {
		cb(settings.reminder);
	});
};

var setReminderState = function(b) {
	kango.invokeAsync('kango.storage.getItem', 'rose-settings', function(settings) {
		settings.reminder = b;
		kango.invokeAsync('kango.storage.setItem', 'rose-settings', settings);
	});
};